package com.liziba.unsafe;

import com.liziba.unsafe.pojo.User;
import sun.misc.Unsafe;

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

/**
 * <p>
 *      操作对象示例
 * </p>
 *
 * @Author: Liziba
 * @Date: 2021/5/24 20:40
 */
public class OperateObjectExample {

    /**
     *  1、public native Object allocateInstance(Class<?> var1); 分配内存
     *  2、public native Class<?> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6); 方法定义一个类用于动态的创建类
     * @throws Exception
     */
    public static void operateObjectUseUnsafe() throws Exception{

        Unsafe unsafe = UnsafeFactory.getUnsafe();

        // 使用Unsafe的allocateInstance()方法，可以无需使用构造函数的情况下实例化对象
        User user = (User) unsafe.allocateInstance(User.class);
        user.setId(1);
        user.setName("李子捌");
        System.out.println(user);

        // 返回对象成员属性在内存中相对于对象在内存中地址的偏移量
        Field name = User.class.getDeclaredField("name");
        long fieldOffset = unsafe.objectFieldOffset(name);

        // 使用Unsafe的putXxx()方法，可以直接修改内存地址指向的数据（可以越过权限访问控制符）
        unsafe.putObject(user, fieldOffset, "李子柒");
        System.out.println(user);

        // 使用Unsafe在运行时通过.class文件，创建类
        File classFile = new File("E:\\workspaceall\\liziba-javap5\\out\\production\\liziba-javap5\\com\\liziba\\unsafe\\pojo\\User.class");
        FileInputStream fis = new FileInputStream(classFile);
        byte [] classContent = new byte[(int) classFile.length()];
        fis.read(classContent);
        Class<?> clazz = unsafe.defineClass(null, classContent, 0, classContent.length, null, null);
        Constructor<?> constructor = clazz.getDeclaredConstructor(int.class, String.class);
        System.out.println(constructor.newInstance(1, "李子玖"));

    }

    public static void main(String[] args) {
        try {
            OperateObjectExample.operateObjectUseUnsafe();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
